﻿using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Web;
using System.Web.Mvc;
using System.Web.Mvc.Html;
using Super.Common;
using Super.Common.Strings;

namespace System
{
    public static class ExtentionMethod
    {


        /// <summary> 尝试类型转换. 如转换失败有较多的性能损耗.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="sender"></param>
        /// <param name="defultValue"> </param>
        /// <returns></returns>
        public static T As<T>(this object sender, Func<T> defultValue)
        {
            if (sender == null)
            {
                return defultValue();
            }

            if (sender is T)
            {
                return (T)sender;
            }

            var tt = typeof(T);

            var converter = TypeDescriptor.GetConverter(tt);
            if (converter.CanConvertFrom(sender.GetType()))
            {
                return (T)converter.ConvertFrom(sender);
            }

            // try the other direction 
            converter = TypeDescriptor.GetConverter(sender.GetType());
            if (converter.CanConvertTo(tt))
            {
                return (T)converter.ConvertTo(sender, tt);
            }

            if (tt.BaseType == typeof(Enum))
            {
                return (T)Enum.ToObject(tt, sender.As(0L));
            }

            if (sender.GetType().IsEnum)
            {
                return (T)Convert.ChangeType(sender, typeof(T));
            }

            //try
            //{
            //    //这一行在报错时,性能低下..应该没有用得上这一行的地方.
            //    //return (T)Convert.ChangeType(sender, typeof(T));
            //}
            //catch
            //{
            //}
            return defultValue();

        }

        /// <summary> 尝试类型转换. 如转换失败有较多的性能损耗.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="sender"></param>
        /// <param name="defultValue"></param>
        /// <returns></returns>
        public static T As<T>(this object sender, T defultValue = default(T))
        {
            return sender.As(() => defultValue);

        }



        /// <summary> string 转 int
        /// </summary>
        /// <param name="isReturnZero">异常时,返回 defaultValue </param>
        /// <param name="str"></param>
        /// <returns>正常返回int值，不正常返回int.MinValue</returns>
        public static int ToInt(this string str, int defaultValue = int.MinValue)
        {
            var ot = 0;
            return int.TryParse(str, out ot) ? ot : defaultValue;
        }

        /// <summary> string to boolean.
        /// </summary>
        /// <param name="str"></param>
        /// <returns>若符合bool类型的string则返回bool，否则返回bool?的null值。</returns>
        public static bool? ToBoolean(this string str, bool? defaultValue = null)
        {
            bool? returnValue = null;
            if (str.ToLower() == true.ToString().ToLower())
            {
                returnValue = true;
            }
            else if (str.ToLower() == false.ToString().ToLower())
            {
                returnValue = false;
            }
            else
            {
                returnValue = defaultValue;
            }
            return returnValue;
        }

        /// <summary> string 转 decimal
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public static decimal ToDecimal(this string str, decimal defaultValue = decimal.MinValue)
        {
            decimal rt;
            return decimal.TryParse(str, out rt) ? rt : defaultValue;
        }

        /// <summary> string 转 datetime
        /// </summary>
        /// <param name="str"></param>
        /// <param name="defaultValue"></param>
        /// <returns>成功返回 datetime 失败返回 null</returns>
        public static DateTime? ToDateTime(this string str, DateTime? defaultValue = null)
        {
            str = str ?? "";
            return PageValidate.IsDateTime(str) ? Convert.ToDateTime(str) : defaultValue;
        }

        /// <summary> string 转 double
        /// </summary>
        /// <param name="str"></param>
        /// <param name="defaultValue"></param>
        /// <returns></returns>
        public static double ToDouble(this string str, double defaultValue = double.MinValue)
        {
            double rt;
            return Double.TryParse(str, out rt) ? rt : defaultValue;
        }

        public static string ToScriptMessage(this string str)
        {
            return str.Replace("\r\n", "<br/>")
                   .Replace("'", "\\'")
                   .Replace("\"", "\\\"");
        }

        public static HtmlString ToHtml(this string str)
        {
            return new HtmlString(str);
        }

        /// <summary> 转换路径地址到assets域 [这个将要废弃]
        /// </summary>
        /// <param name="urlhelper"></param>
        /// <param name="filePath">文件在Assets网站中的相对路径。</param>
        /// <returns>返回文件的路径。</returns>
        public static string Get(this UrlHelper urlhelper, string filePath)
        {
            var mt = new StackTrace(true).GetFrame(1);
            var fileName = mt.GetFileName();
            var num = 0;
            if (fileName != null)
            {
                num = mt.GetFileLineNumber();
            }

            var ex = new Exception("Shit! 方法废弃了 详情请看wiki http://www.wiki.com PageName=" + fileName + ";LineNumber=" + num);

            throw ex;
        }

        /// <summary> 转换路径地址到assets域
        /// </summary>
        /// <param name="urlhelper"></param>
        /// <param name="filePath">文件在Assets网站中的相对路径。</param>
        /// <returns>返回文件的路径。</returns>
        public static string GetAssets(this UrlHelper urlhelper, string filePath)
        {
            var mt = new StackTrace(true).GetFrame(1);
            var fileName = mt.GetFileName();
            var num = 0;
            if (fileName != null)
            {
                num = mt.GetFileLineNumber();
            }

            var ex = new Exception("Shit! 方法废弃了 详情请看wiki http://www.wiki.com PageName=" + fileName + ";LineNumber=" + num);

            throw ex;
        }

        /// <summary> 转换路径地址到assets域脚本
        /// </summary>
        /// <param name="urlhelper"></param>
        /// <param name="filePath">文件在Assets网站中的相对路径。</param>
        /// <returns>返回文件的路径。</returns>
        public static string GetScript(this UrlHelper urlhelper, string filePath)
        {
            var mt = new StackTrace(true).GetFrame(1);
            var fileName = mt.GetFileName();
            var num = 0;
            if (fileName != null)
            {
                num = mt.GetFileLineNumber();
            }

            var ex = new Exception("Shit! 方法废弃了 详情请看wiki http://www.wiki.com PageName=" + fileName + ";LineNumber=" + num);

            throw ex;
        }

        /// <summary> 统一格式化帮客网的时间格式
        /// </summary>
        /// <param name="datetime"></param>
        /// <param name="timeAccurate">时间格式枚举 </param>
        /// <returns></returns>
        public static string ToBangkeDateTime(this DateTime datetime, TimeAccurate timeAccurate = TimeAccurate.Minute)
        {
            string timeFormat = "yyyy-MM-dd HH:mm";

            switch (timeAccurate)
            {
                case TimeAccurate.Date:
                    timeFormat = "yyyy-MM-dd";
                    break;
                case TimeAccurate.Minute:
                    timeFormat = "yyyy-MM-dd HH:mm";
                    break;
                case TimeAccurate.Seconds:
                    timeFormat = "yyyy-MM-dd HH:mm:ss";
                    break;
            }

            return datetime.ToString(timeFormat);
        }


        /// <summary> 按字节大小截取字符串
        /// </summary>
        /// <param name="old"></param>
        /// <param name="CutNum">截取的长度,中文2个字节，英文1个</param>
        /// <param name="noHtml">是否格式化html</param>
        /// <returns></returns>
        public static string Cut(this string old, int CutNum = 50, bool noHtml = false)
        {
            return (noHtml)
                       ? StringPlus.SubStrByByte(old.RemoveHtmlTaget(), CutNum)
                       : StringPlus.SubStrByByte(old, CutNum);
        }

        /// <summary> View 的 Html 扩展方法
        /// </summary>
        /// <param name="htmlHelper"></param>
        /// <returns></returns>
        public static string HtmlHelperEx(this HtmlHelper htmlHelper)
        {
            return htmlHelper.ToString();
        }

        /// <summary> 为 BeginForm 自动添加 id 和 name
        /// </summary>
        /// <param name="htmlHelper"></param>
        /// <returns></returns>
        public static MvcForm BeginBKForm(this HtmlHelper htmlHelper, string controller = null, string action = null)
        {
            return htmlHelper.BeginForm(controller, action, FormMethod.Post, new { @id = "bkform", @name = "bkform" });
        }


        /// <summary> 修改html标签[将'<'和'>'修改成&lt;和&gt;]
        /// </summary>
        /// <param name="oldStr">含有标签的字符串。</param>
        /// <returns>返回已转化的标签。</returns>
        public static string ChangTag(this string oldStr)
        {
            return oldStr.Replace("<", "&lt;").Replace(">", "&gt;");
        }

        /// <summary> 去除HTML标签脚本
        /// </summary>
        /// <param name="htmlStr"></param>
        /// <returns></returns>
        public static string RemoveHtmlTaget(this string htmlStr)
        {
            //删除脚本
            htmlStr = htmlStr.Replace("\r\n", "");
            htmlStr = Regex.Replace(htmlStr, @"<script.*?</script>", "", RegexOptions.IgnoreCase);
            htmlStr = Regex.Replace(htmlStr, @"<style.*?</style>", "", RegexOptions.IgnoreCase);
            htmlStr = Regex.Replace(htmlStr, @"<.*?>", "", RegexOptions.IgnoreCase);
            //删除HTML
            htmlStr = Regex.Replace(htmlStr, @"<(.[^>]*)>", "", RegexOptions.IgnoreCase);
            htmlStr = Regex.Replace(htmlStr, @"([\r\n])[\s]+", "", RegexOptions.IgnoreCase);
            htmlStr = Regex.Replace(htmlStr, @"-->", "", RegexOptions.IgnoreCase);
            htmlStr = Regex.Replace(htmlStr, @"<!--.*", "", RegexOptions.IgnoreCase);
            htmlStr = Regex.Replace(htmlStr, @"&(quot|#34);", "\"", RegexOptions.IgnoreCase);
            htmlStr = Regex.Replace(htmlStr, @"&(amp|#38);", "&", RegexOptions.IgnoreCase);
            htmlStr = Regex.Replace(htmlStr, @"&(lt|#60);", "<", RegexOptions.IgnoreCase);
            htmlStr = Regex.Replace(htmlStr, @"&(gt|#62);", ">", RegexOptions.IgnoreCase);
            htmlStr = Regex.Replace(htmlStr, @"&(nbsp|#160);", "", RegexOptions.IgnoreCase);
            htmlStr = Regex.Replace(htmlStr, @"&(iexcl|#161);", "\xa1", RegexOptions.IgnoreCase);
            htmlStr = Regex.Replace(htmlStr, @"&(cent|#162);", "\xa2", RegexOptions.IgnoreCase);
            htmlStr = Regex.Replace(htmlStr, @"&(pound|#163);", "\xa3", RegexOptions.IgnoreCase);
            htmlStr = Regex.Replace(htmlStr, @"&(copy|#169);", "\xa9", RegexOptions.IgnoreCase);
            htmlStr = Regex.Replace(htmlStr, @"&#(\d+);", "", RegexOptions.IgnoreCase);
            htmlStr = htmlStr.Replace("<", "");
            htmlStr = htmlStr.Replace(">", "");
            htmlStr = htmlStr.Replace("\r\n", "");
            //htmlStr = HttpContext.Current.Server.HtmlEncode(htmlStr).Trim();
            return htmlStr;
        }

        #region Terry扩展

        /// <summary> ToList ,分隔
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="?"></param>
        /// <param name="str"></param>
        /// <param name="splitStr"></param>
        /// <param name="isRemoveEmptyEntries"></param>
        /// <returns></returns>
        public static List<string> SplitList(this string str, char splitStr = ',', bool isRemoveEmptyEntries = true)
        {
            return str.Split(splitStr).Where(j => j != null).ToList();
        }

        /// <summary> 添加元素
        /// </summary>
        /// <param name="str"></param>
        /// <param name="value"></param>
        /// <param name="splitStr"></param>
        /// <param name="isAlloyRepeat"></param>
        /// <returns></returns>
        public static string SplitAdd(this string str, string value, char splitStr = ',', bool isAlloyRepeat = false)
        {
            var v = str.SplitList(splitStr);
            var b = v.Exists(j => j == value);
            if (b && !isAlloyRepeat)
                return str;
            else
            {
                v.Add(value);
                return v.JoinToString(splitStr);
            }
        }

        /// <summary> 移除元素
        /// </summary>
        /// <param name="str"></param>
        /// <param name="value"></param>
        /// <param name="splitStr"></param>
        /// <returns></returns>
        public static string SplitRemove(this string str, string value, char splitStr = ',')
        {
            var v = str.SplitList(splitStr);
            v.Remove(value);
            return v.JoinToString(splitStr);
        }

        /// <summary> 判断元素是否存在
        /// </summary>
        /// <param name="str"></param>
        /// <param name="value"></param>
        /// <param name="splitStr"></param>
        /// <returns></returns>
        public static bool SplitExits(this string str, string value, char splitStr = ',')
        {
            return str.SplitList(splitStr).Exists(j => j == value);
        }

        /// <summary> 连接并返回字符串
        /// </summary>
        /// <param name="list"></param>
        /// <param name="splitStr"></param>
        /// <returns></returns>
        public static string JoinToString(this List<string> list, char splitStr)
        {
            return JoinToString(list, splitStr.ToString());
        }
        /// <summary> 连接并返回字符串
        /// </summary>
        /// <param name="list"></param>
        /// <param name="splitStr"></param>
        /// <returns></returns>
        public static string JoinToString(this List<string> list, string splitStr = ",")
        {
            if (list.Count > 0)
                if (list.Count > 100)
                {
                    var sb = new StringBuilder(list[0]);
                    for (int i = 1; i < list.Count; i++)
                    {
                        sb.Append(splitStr + list[i]);
                    }
                    return sb.ToString();
                }
                else
                {
                    string s = list[0];
                    for (int i = 1; i < list.Count; i++)
                    {
                        s += splitStr + list[i];
                    }
                    return s;
                }
            return "";
        }

        /// <summary> 格式化字符串
        /// </summary>
        /// <param name="str"></param>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static string FormatMe(this string str, params object[] obj)
        {
            return string.Format(str, obj);
        }

        /// <summary> 字符串转换Byte数组.
        /// </summary>
        /// <param name="str"></param>
        /// <param name="cd"></param>
        /// <returns></returns>
        public static byte[] ToBytes(this string str, Encoding cd = null)
        {
            return (cd ?? Encoding.Default).GetBytes(str);
        }

        /// <summary> 尝试获取Value. 如果不存在,则通过委托增加Value并返回.
        /// </summary>
        /// <typeparam name="TKey"></typeparam>
        /// <typeparam name="TValue"></typeparam>
        /// <param name="dic"></param>
        /// <param name="key">Key</param>
        /// <param name="func">如果Key不存在,则通过委托创建Key</param>
        /// <returns></returns>
        public static TValue TryGet<TKey, TValue>(this Dictionary<TKey, TValue> dic, TKey key, Func<TValue> func)
        {
            return dic.ContainsKey(key) ? dic[key] : (dic[key] = func());
        }

        /// <summary> 尝试使Value自增. 如果key不存在,则默认Value=0,返回1
        /// </summary>
        /// <typeparam name="TKey"></typeparam> 
        /// <param name="dic"></param>
        /// <param name="key"></param> 
        /// <returns></returns>
        public static int TryInc<TKey>(this Dictionary<TKey, int> dic, TKey key)
        {
            return dic.ContainsKey(key) ? ++dic[key] : dic[key] = 1;
        }

        /// <summary> 尝试是Value自减. 如果key不存在,则默认Value=0,返回-1
        /// </summary>
        /// <typeparam name="TKey"></typeparam>
        /// <param name="dic"></param>
        /// <param name="key"></param>
        /// <returns></returns>
        public static int TryDec<TKey>(this Dictionary<TKey, int> dic, TKey key)
        {
            return dic.ContainsKey(key) ? --dic[key] : dic[key] = -1;
        }

        #endregion

    }

    /// <summary> 帮客统一时间精确度
    /// </summary>
    public enum TimeAccurate
    {
        /// <summary> 精确到日期
        /// </summary>
        Date,

        /// <summary> 精确到分钟
        /// </summary>
        Minute,

        /// <summary> 精确到秒
        /// </summary>
        Seconds
    }
}